package in.lib.exception; import in.lib.Debug; import in.lib.manager.CacheManager; import in.model.CrashReport; import in.model.Settings; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FilenameFilter; import java.io.InputStream; import java.io.ObjectInputStream; import java.io.ObjectOutput; import java.io.ObjectOutputStream; import java.io.Serializable; import lombok.Getter; import net.callumtaylor.asynchttp.AsyncHttpClient; import net.callumtaylor.asynchttp.obj.entity.JsonEntity; import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.os.Handler; import android.os.Looper; import android.provider.Settings.Secure; public class ExceptionHandler { @Getter private String reportUrl = "localhost"; @Getter private String filesPath = "/"; private String[] stackTraceFileList = null; private static ExceptionHandler instance; public static ExceptionHandler getInstance() { if (instance == null) { synchronized (ExceptionHandler.class) { if (instance == null) { instance = new ExceptionHandler(); } } } return instance; } /** * @return Gets the base 64 rehashable id of the device */ public String getDeviceId(Context c) { // Create re-hashable password for the device String deviceId = Secure.getString(c.getContentResolver(), Secure.ANDROID_ID); deviceId = deviceId == null ? "NOID" + System.currentTimeMillis() : deviceId; // Now we hash it and b64 it String deviceHash = CacheManager.getHash(deviceId); return deviceHash; } public void register(Context context, String url) { reportUrl = url; try { PackageManager pm = context.getPackageManager(); PackageInfo pi = pm.getPackageInfo(context.getPackageName(), 0); Settings.PACKAGE_NAME = pi.packageName; Settings.VERSION = "" + pi.versionName; Settings.VERSION_CODE = "" + pi.versionCode; Settings.DEVICE_ID = getDeviceId(context); } catch (Exception e) { Debug.out(e); } try { filesPath = context.getExternalCacheDir().getAbsolutePath() + "/crash_reports"; } catch (Exception e) { filesPath = context.getFilesDir().getAbsolutePath() + "/crashes/"; } new Thread() { @Override public void run() { submitStackTraces(); UncaughtExceptionHandler currentHandler = Thread.getDefaultUncaughtExceptionHandler(); // don't register again if already registered if (!(currentHandler instanceof DefaultExceptionHandler)) { Thread.setDefaultUncaughtExceptionHandler(new DefaultExceptionHandler(currentHandler)); } } }.start(); } /** * Forces a manual exception post * @param e */ public static void sendException(Exception e) { DefaultExceptionHandler.sendException(e, "CAUGHT EXCEPTION"); } /** * Search for stack trace files. * * @return */ private String[] searchForStackTraces() { try { if (stackTraceFileList != null) { return stackTraceFileList; } File dir = new File(filesPath); // Try to create the files folder if it doesn't exist dir.mkdir(); FilenameFilter filter = new FilenameFilter() { @Override public boolean accept(File dir, String name) { return name.endsWith(".stacktrace"); } }; return (stackTraceFileList = dir.list(filter)); } catch (Exception e) { return new String[]{}; } } /** * Look into the files folder to see if there are any "*.stacktrace" files. * If any are present, submit them to the trace server. */ public void submitStackTraces() { String[] list = searchForStackTraces(); try { if (list != null && list.length > 0) { for (int i = 0; i < list.length; i++) { String filename = list[i]; final CrashReport report = readFileAsObject(filesPath, filename, CrashReport.class); boolean result = new Handler(Looper.getMainLooper()).post(new Runnable() { @Override public void run() { try { AsyncHttpClient c = new AsyncHttpClient(reportUrl); JsonEntity entity = report.toEntity(); c.post(entity, null); } catch (Exception e) { Debug.out(e); } } }); File file = new File(filesPath, filename); file.delete(); } } } catch (Exception e) { Debug.out(e); } } public static <T> T readFileAsObject(String filesPath, String fileName, Class<T> outClass) { try { return outClass.cast(desterializeObject(readFile(new FileInputStream(new File(filesPath, fileName))))); } catch (Exception e) { Debug.out(e); return null; } } public static void writeFile(String filesPath, String fileName, Serializable contents) { FileOutputStream fos = null; try { if (fos == null) { File f = new File(filesPath, fileName); fos = new FileOutputStream(f); } fos.write(serializeObject(contents)); fos.flush(); fos.close(); } catch (Exception e) { Debug.out(e); } } public static byte[] readFile(InputStream input) { ByteArrayOutputStream bos = null; try { bos = new ByteArrayOutputStream(8192); int bufferSize = 1024; byte[] buffer = new byte[bufferSize]; int len = 0; while ((len = input.read(buffer)) > 0) { bos.write(buffer, 0, len); } return bos.toByteArray(); } catch (Exception e) { Debug.out(e); } finally { try { input.close(); bos.close(); } catch (Exception e) { Debug.out(e); } } return null; } public static Object desterializeObject(byte[] data) { try { ObjectInputStream input = new ObjectInputStream(new ByteArrayInputStream(data)); Object objectData = input.readObject(); input.close(); return objectData; } catch (Exception e) { Debug.out(e); return null; } } public static byte[] serializeObject(Object data) { try { ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutput out = new ObjectOutputStream(bos); out.writeObject(data); byte[] yourBytes = bos.toByteArray(); return yourBytes; } catch (Exception e) { Debug.out(e); return null; } } }